from _datetime import datetime
import re
import hashlib
import json
import os
import platform
import shutil
import stat
import subprocess
from typing import List

from PySide2.QtCore import Qt, QRect
from PySide2.QtWidgets import QMainWindow, QDesktopWidget, QTableWidget
from xlrd import Book

import Logger
from ExcelData import EData
from lib import ExcelLibLoader
from lib.ExcelLibDefinitionMain import ExcelLibDefinitionMain


def isSheetExist(workbook: Book, sheetName: str):
    """检查是否存在该页面\n
    isSheetExist(Book, str) --> bool
    """
    for sname in workbook.sheet_names():
        if sheetName == sname:
            return True
    return False


def parseInt(strValue: str, defaultValue):
    """把字符转为int, 如果失败则返回defaultValue"""
    value: int
    try:
        value = int(strValue)
    except:
        value = defaultValue
    return value


def getDateTimeString(covertTime: datetime):
    """获取时间字符"""
    if covertTime is None:
        return ""
    return covertTime.strftime("%Y-%m-%d %H:%M:%S")

def hasSpecifyString(string, prefix):
    pattern = r'^(?=.*(' + prefix + '))'
    return bool(re.match(pattern, string))

def getDataTimeFromString(timeString: str):
    """从时间字符串转为时间datetime"""
    return datetime.strptime(timeString, "%Y-%m-%d %H:%M:%S")


def getVersionString(covertTime: datetime):
    """获取时间字符"""
    if covertTime is None:
        return ""
    return covertTime.strftime("V.%y%m%d.%H%M.%S")


def openFilePath(fp: str):
    """
	打开文件或文件夹
	优点: 代码输入参数少, 复制粘贴即可使用, 支持在mac和win上使用, 打开速度快稳定;
	:param fp: 需要打开的文件或文件夹路径
	"""
    systemType: str = platform.platform()  # 获取系统类型
    if 'mac' in systemType:  # 判断以下当前系统类型
        fp: str = fp.replace("\\", "/")  # mac系统下,遇到`\\`让路径打不开,不清楚为什么哈,觉得没必要的话自己可以删掉啦,18行那条也是
        subprocess.call(["open", fp])
    else:
        fp: str = fp.replace("/", "\\")  # win系统下,有时`/`让路径打不开
    os.startfile(fp)


# def deleteDirectoryTree(path):
#     ''' 递归删除目录及其子目录,　子文件'''
#
#     if os.path.isfile(path):
#         try:
#             if not specifyExtFilename is None:
#                 ext: str = os.path.splitext(path)[-1]
#                 if ext.lower() == specifyExtFilename.lower():
#             os.chmod(path, stat.S_IWRITE)  # .svn内文件是只读文件，要删除必须先设置属性
#             os.remove(path)
#         except Exception as e:
#             print(e)
#     elif os.path.isdir(path):
#         for item in os.listdir(path):
#             itempath = os.path.join(path, item)
#             deleteDirectoryTree(itempath)  # 递归删除
#         try:
#             os.rmdir(path)  # 删除空目录
#         except Exception as e:
#             # pass
#             print(e)

def getVersionCode(versionStr: str):
    if len(versionStr) < 1:
        return 0;
    version: str = ""
    for i in range(len(versionStr)):
        try:
            x = int(versionStr[i])
            version = version + versionStr[i]
        except:
            pass
    if len(version) < 1:
        return 0;
    return int(version)

def deleteDirectoryFiles(path, includeSubDir: bool = True, specifyExtFilename: str = None):
    if not specifyExtFilename is None:
        if specifyExtFilename == "" or specifyExtFilename.find("*") > -1:
            specifyExtFilename = None
        else:
            if not specifyExtFilename.startswith("."):
                specifyExtFilename = "." + specifyExtFilename
    if not isDirAndExists(path):
        return;
    __deleteDirectoryFiles(path, includeSubDir, specifyExtFilename, 0)


def __deleteDirectoryFiles(path, includeSubDir: bool = True, specifyExtFilename: str = None, depth: int = 0):
    for item in os.listdir(path):
        itemPath = os.path.join(path, item)
        if os.path.isfile(itemPath):
            if not specifyExtFilename is None:
                ext: str = os.path.splitext(itemPath)[-1]
                if ext.lower() != specifyExtFilename.lower():
                    return  # 如果需要判断扩展名但扩展名不对则退出
            try:
                os.chmod(itemPath, stat.S_IWRITE)  # 文件是只读文件，要删除必须先设置属性
                os.remove(itemPath)
            except Exception as e:
                print(e)
        elif os.path.isdir(itemPath) and includeSubDir:
            __deleteDirectoryFiles(itemPath, includeSubDir, specifyExtFilename, depth + 1)  # 递归删除
            try:
                os.rmdir(itemPath)  # 删除空目录
            except Exception as e:
                print(e)


def tryCreateDirectory(dirPath):
    """如果目录不存在就创建目录"""
    if not os.path.exists(dirPath) or not os.path.isdir(dirPath):
        os.makedirs(dirPath)


def getCodePath(appPath: str, settingVoPath: str):
    """获取代码生成真实路径。获取失败会返回None"""
    if not os.path.isabs(settingVoPath):  # 检查是否绝对路径
        settingVoPath = appPath + settingVoPath  # 非绝对路径则加上执行目录
        settingVoPath = settingVoPath.replace("\\\\", "\\")  # 去掉双重\\的路径
    if not os.path.exists(settingVoPath) or not os.path.isdir(settingVoPath):
        # self.logger.logWarning("检测目录不存在，自动创建：" + settingVoPath)
        tryCreateDirectory(settingVoPath)
    return settingVoPath


def isFileAndExists(filePath):
    """判断本地路径，是否文件与是否存在"""
    if os.path.exists(filePath) and os.path.isfile(filePath):
        return True
    else:
        return False


def isDirAndExists(filePath):
    """判断本地路径，是否文件夹目录与是否存在"""
    if os.path.exists(filePath) and os.path.isdir(filePath):
        return True
    else:
        return False


def copyDirectoryFiles(srcPath, destPath, includeSubDir: bool = False, ignoreDirs: List[str] = []):
    """拷贝目录下（本层）的所有文件"""
    if not os.path.exists(srcPath):
        print("srcpath not exist!")
    if not os.path.exists(destPath):
        print("dstpath not exist!")

    for item in os.listdir(srcPath):
        copyPath = os.path.join(srcPath, item)
        if os.path.isfile(copyPath):  # 只拷贝文件
            shutil.copy(copyPath, destPath)
        elif os.path.isdir(copyPath) and includeSubDir:
            isSkip: bool = False
            for dir in ignoreDirs:
                if dir.lower() == item.lower():
                    isSkip = True
            if isSkip:
                continue
            destPathSub = os.path.join(destPath, item)
            os.makedirs(destPathSub)
            copyDirectoryFiles(copyPath, destPathSub)


def getMd5(data):
    m = hashlib.md5()
    m.update(data.encode('utf-8'))
    return m.hexdigest()


def getComputerName():
    """获取计算机名"""
    computerName = os.environ.get("COMPUTERNAME")
    return computerName


def getChineseTimeDifference(oldTime: datetime):
    """返回中文显示的时间相差距离"""
    if oldTime == None:
        return ""
    now: datetime = datetime.now()
    print("oldTime" + str(oldTime))
    differ = now - oldTime
    m, s = divmod(differ.seconds, 60)
    fh = m / 60
    h, m = divmod(m, 60)
    if differ.days > 0:
        diffStr = str(differ.days) + "天前"
    elif differ.seconds > 3600:
        diffStr = "%.1f小时前" % (fh)
    elif differ.seconds > 60:
        diffStr = "%d分钟前" % (m)
    else:
        diffStr = "刚刚"
    return diffStr


def fixUrlBackslash(url: str, isCompltionEndSlash: bool = False):
    """
    修正网址的反斜杠，在最后补反斜杠，去掉双反斜杠
    :param url: 网址
    :param isCompltionEndSlash 是否在最后补充一个斜杠
    :return: 修正后路径
    """
    url = url.replace("\\", "/")
    url = url.replace("://", ":||")
    while url.find("//") >= 0:
        url = url.replace("//", "/")
    if isCompltionEndSlash:
        if not url.endswith("/"):
            url += "/"
    url = url.replace(":||", "://")
    return url


def fixPathSlash(path: str, isCompltionEndSlash: bool = False):
    """
    修正目录路径的斜杠，在最后补斜杠，去掉双斜杠
    :param path: 路径
    :param isCompltionEndSlash 是否在最后补充一个斜杠
    :return: 修正后路径
    """
    path = path.replace("/", "\\")
    while path.find("\\\\") >= 0:
        path = path.replace("\\\\", "\\")
    if isCompltionEndSlash:
        if not path.endswith("\\"):
            path += "\\"
    return path


mainForm: QMainWindow
"""实例窗体"""


def setToTop(window):
    flags = window.windowFlags()
    window.setWindowFlags(flags | Qt.WindowStaysOnTopHint)
    window.show()
    window.setWindowFlags(flags)
    window.show()


def getScreenRect():
    return QDesktopWidget().screenGeometry()


HEADER_STYLE_GRAY = 1
HEADER_STYLE_YELLOW = 2
HEADER_STYLE_BLUE = 3
HEADER_STYLE_GREEN = 4


def initColumnListFile(list: QTableWidget, columnNames: List[str], columnWidth: List[int] = None, headStyle: int = 1):
    # 设置表头样式
    list.setColumnCount(len(columnNames))
    list.setHorizontalHeaderLabels(columnNames)
    if headStyle == HEADER_STYLE_YELLOW:
        list.horizontalHeader().setStyleSheet('''
            ::section {
                background-color: #FFEE99;
                border-style: solid;
                border-color: #BBBBBB;
                border-width: 1px;
                padding: 0px 0px;
                font-weight:bold;
                }''')
    elif headStyle == HEADER_STYLE_BLUE:
        list.horizontalHeader().setStyleSheet('''
            ::section {
                background-color: #C7EEFF;
                border-style: solid;
                border-color: #BBBBBB;
                border-width: 1px;
                padding: 0px 0px;
                font-weight:bold;
                }''')
    elif headStyle == HEADER_STYLE_GREEN:
        list.horizontalHeader().setStyleSheet('''
            ::section {
                background-color: #C9FFD3;
                border-style: solid;
                border-color: #BBBBBB;
                border-width: 1px;
                padding: 0px 0px;
                font-weight:bold;
                }''')
    elif headStyle == HEADER_STYLE_GRAY:
        list.horizontalHeader().setStyleSheet('''
            ::section {
                background-color: #EEEEEE;
                border-style: solid;
                border-color: #BBBBBB;
                border-width: 1px;
                padding: 0px 0px;
                font-weight:bold;
                }''')
    if not columnWidth is None:
        for i in range(0, len(columnWidth)):
            list.setColumnWidth(i, columnWidth[i])
    list.horizontalHeader().setStretchLastSection(True)


def getDefinition(filepath: str):
    # 读取该目录的definition.json文件
    edata = EData()
    logger = Logger.Logger()
    definitionFn: str = os.path.join(filepath, edata.setting.defDefineJsonFile)
    if not isFileAndExists(definitionFn):
        logger.logError("你选择的数据包_definition.json数据错误！")
        return None
    with open(definitionFn, 'r', encoding='utf8') as f:
        defineJsonData = json.load(f)
    if defineJsonData is None:
        logger.logError("你选择的数据包_definition.json数据读取错误！")
        return None
    definition: ExcelLibDefinitionMain = ExcelLibLoader.parseDefinitionMainFromJson(defineJsonData)
    return definition
